package com.pine.app.module.security.oauth.filter;

import com.pine.app.module.security.core.SecurityContextHolder;
import com.pine.app.module.security.core.exception.AccessDeniedException;
import com.pine.app.module.security.core.exception.BaseException;
import com.pine.app.module.security.core.exception.DefaultExceptionEntryPoint;
import com.pine.app.module.security.core.exception.ExceptionEntryPoint;
import com.pine.app.module.security.core.web.BaseWebFilter;
import com.pine.app.module.security.oauth.exception.AuthenticationException;
import com.pine.app.module.security.oauth.exception.analyzer.DefaultThrowableAnalyzer;
import com.pine.app.module.security.oauth.exception.analyzer.ThrowableAnalyzer;
import org.springframework.core.annotation.Order;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 异常处理拦截器  跳转页面或者返回json数据
 *
 * @author xiaoyuan
 * @create 2020/3/11 13:14
 **/
@Order(10)
public class ExceptionTranslationFilter extends BaseWebFilter {

    private ThrowableAnalyzer throwableAnalyzer;
    private ExceptionEntryPoint exceptionEntryPoint;

    public ExceptionTranslationFilter() {
        this.throwableAnalyzer = new DefaultThrowableAnalyzer();
        exceptionEntryPoint = new DefaultExceptionEntryPoint();
    }

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        try {
            filterChain.doFilter(httpServletRequest, httpServletResponse);
            successHandler();
        } catch (IOException e) {
            throw e;
        } catch (Exception e) {

            Throwable[] causeChain = this.throwableAnalyzer.determineCauseChain(e);
            BaseException exception = (BaseException) this.throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class, causeChain);
            if (exception == null) {
                exception = (BaseException) this.throwableAnalyzer.getFirstThrowableOfType(AccessDeniedException.class, causeChain);
            }
            if (exception == null) {
                if (e instanceof ServletException) {
                    throw (ServletException) e;
                }
                if (e instanceof RuntimeException) {
                    throw (RuntimeException) e;
                }
                throw new RuntimeException(e);
            }
            if (httpServletResponse.isCommitted()) {
                throw new ServletException("不能处理异常，因为已经数据已返回", e);
            }
            exceptionHandler(httpServletRequest, httpServletResponse, exception);
        } finally {
            SecurityContextHolder.clearContext();
        }
    }

    private void successHandler() {

    }

    private <T extends BaseException> void exceptionHandler(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, T e) throws IOException, ServletException {
        exceptionEntryPoint.handler(httpServletRequest, httpServletResponse, e);
    }


}
